package com.itheima.service.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.itheima.constant.MessageConstant;
import com.itheima.dao.MenuDao;
import com.itheima.entity.PageResult;
import com.itheima.pojo.Menu;
import com.itheima.service.MenuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.ArrayList;

/**
 * 项目实战--菜单列表服务实现类
 * @author zhengjd
 * @date 2020/4/17 16:23
 */
@Transactional
@Service(interfaceClass = MenuService.class)
public class MenuServiceImpl implements MenuService {

    @Autowired
    MenuDao menuDao;

    /**
     * 根据用户名获取菜单列表
     * @param username
     * @return
     */
    @Override
    public List<Menu> getMenuByUsername(String username) {
        //获取对应用户所拥有的一级菜单
        List<Menu> menuList = menuDao.getMenuLevel1ByUsername(username);
        //判断是否为空
        if (menuList != null && menuList.size()>0){
            for (Menu menu : menuList) {
                //获取菜单的子菜单
                Map<String, Object> map = new HashMap<>();
                map.put("username",username);
                map.put("parentMenuId",menu.getId());
                List<Menu> children = menuDao.getChildrenMenuList(map);
                menu.setChildren(children);
            }
        }
        return menuList;
    }

    @Override
    public PageResult findPage(Integer currentPage, Integer pageSize, String queryString) {
        PageHelper.startPage(currentPage, pageSize);
        //2.需要分页的语句
        Page<Menu> menuPage = menuDao.selectByCondition(queryString);
        return new PageResult(menuPage.getTotal(), menuPage.getResult());
    }

    @Override
    public PageResult findPage2(Integer currentPage, Integer pageSize, String queryString) {
        PageHelper.startPage(currentPage, pageSize);
        //如果没有条件,直接用findPage方法即可
        if (queryString == null || "".equals(queryString)){
            Page<Menu> menuPage = menuDao.selectByCondition(queryString);
            return new PageResult(menuPage.getTotal(), menuPage.getResult());
        }
        Page<Menu> menuPage = menuDao.selectByCondition2(queryString);
        List<Menu> result = menuPage.getResult();
        //被选中的二级菜单ID
        List<Integer> selectedId = new ArrayList<>();
        //循环一级菜单
        if (result == null || result.size() == 0) {
            return new PageResult(menuPage.getTotal(), result);
        }
        for (Menu menu : result) {
            List<Menu> children = menu.getChildren();
            if (children != null && children.size() > 0) {
                //遍历与删除同时进行,通过children.size()遍历
                for (int i = 0; i < children.size(); i++) {
                    Menu child = children.get(i);
                    String name = child.getName();
                    if (name.contains(queryString)) {
                        selectedId.add(child.getId());
                    } else {
                        children.remove(child);
                        i--;//删除后索引回退1
                    }
                }
            }
        }
        //循环二级菜单
        //遍历与删除同时进行,通过children.size()遍历
        for (int i = 0; i < result.size(); i++) {
            Menu menu = result.get(i);
            List<Menu> children = menu.getChildren();
            if (children == null || children.size() == 0) {
                if (selectedId.contains(menu.getId())) {
                    result.remove(menu);
                    i--;//删除后索引回退1
                }
            }
        }
        Long searchChildTotal = menuDao.searchRealTotalChildMenuNumber(queryString);
        Long searchParentTotal = menuDao.searchRealTotalParentMenuNumber(queryString);
        return new PageResult(searchChildTotal + searchParentTotal, result);
    }

    @Override
    public List<Menu> initParentMenu() {
        List<Menu> menuList = menuDao.findAllParentMenu();
        return menuList;
    }

    @Override
    public void add(Menu menu) {
        if (menu.getParentMenuId() == 0) {
            initAddParentMenu(menu);
        } else {
            initAddChildMenu(menu);
        }
        menuDao.addNewMenu(menu);
    }

    public void initAddParentMenu(Menu menu) {
        //true为一级菜单
        Integer newPriority = menu.getPriority();
        menu.setParentMenuId(null);//修改一级菜单的父菜单id为null
        menu.setLevel(1);
        Integer temp = newPriority + 1;
        menu.setPath(temp.toString());
        List<Menu> allParentMenu = menuDao.selectByCondition(null);
        if (allParentMenu != null && allParentMenu.size() > 0) {
            //临时参数tempNum
            Integer tempNum = newPriority;
            for (Menu menuParent : allParentMenu) {
                //当发现有相同Priority时,旗帜参数改为true,后面的菜单开始Priority+1
                if (menuParent.getPriority().equals(tempNum)) {
                    menuParent.setPriority(menuParent.getPriority() + 1);
                    Integer priority = menuParent.getPriority();
                    priority = priority + 1;
                    menuParent.setPath(priority.toString());
                    String path = menuParent.getPath();
                    List<Menu> children = menuParent.getChildren();
                    if (children != null && children.size() > 0) {
                        for (Menu child : children) {
                            child.setPath("/" + path + "-" + child.getPriority());
                            menuDao.editPathAndPriority(child);
                        }
                    }
                    menuDao.editPathAndPriority(menuParent);
                    tempNum = menuParent.getPriority();
                }
                if (menuParent.getPriority()>tempNum){
                    break;
                }
            }
        }
    }

    public void initAddChildMenu(Menu menu) {
        Integer parentMenuId = menu.getParentMenuId();
        Integer newPriority = menu.getPriority();
        //false为二级菜单
        menu.setLevel(2);
        Menu parentMenu = menuDao.findParentMenuByParentMenuId(parentMenuId);
        String parentPath = parentMenu.getPath();
        menu.setPath("/" + parentPath + "-" + newPriority);
        List<Menu> menuList = menuDao.findAllMenuByParentMenuId(menu.getParentMenuId());//已经按照Priority升序排列,保证后续遍历时Priority亦为升序
        //插入前,此处遍历一级菜单所有旧的子菜单,为了保证Priority不重复,若重复则从相同Priority菜单开始,后续菜单Priority+1
        Integer tempNum = newPriority;
        if (menuList != null && menuList.size() > 0) {
            for (Menu menuChild : menuList) {
                if (menuChild.getPriority().equals(tempNum)) {
                    menuChild.setPriority(menuChild.getPriority() + 1);
                    Integer priority = menuChild.getPriority();
                    priority = priority + 1;
                    String path = menuChild.getPath();
                    List<Menu> children = menuChild.getChildren();
                    menuChild.setPath("/" + parentPath + "-" + menuChild.getPriority());
                    menuDao.editPathAndPriority(menuChild);
                    tempNum = menuChild.getPriority();
                }
                if (menuChild.getPriority()>tempNum){
                    break;
                }
            }
        }
    }

    @Override
    public Menu findMenuById(Integer menuId) {
        Menu menu = menuDao.findMenuById(menuId);
        Integer parentMenuId = menu.getParentMenuId();
        if (parentMenuId == null) {
            menu.setParentMenuId(0);
        }
        return menu;
    }

    @Override
    public void edit(Menu menu) {
        //上级目录是否改变的旗帜变量
        Boolean parentChangeFlag = false;
        //显示排序是否改变的旗帜变量
        Boolean priorityChangeFlag = false;
        //得到数据库中的同ID的dbMenu
        Menu dbMenu = menuDao.findMenuById(menu.getId());
        //若数据库中dbMenu的上级目录id=null则改为0,保证前后端统一和便于对比
        if (dbMenu.getParentMenuId() == null){
            dbMenu.setParentMenuId(0);
        }
        //得到menu和dbMenu,开始作对比,先对比上级目录是否改变
        if (!menu.getParentMenuId().equals(dbMenu.getParentMenuId())){
            parentChangeFlag = true;
        }
        //对比显示排序是否改变
        if (!menu.getPriority().equals(dbMenu.getPriority())){
            priorityChangeFlag = true;
        }
        //如果上级目录和显示排序均无改变,则是简单编辑
        if (!parentChangeFlag && !priorityChangeFlag){
            menuDao.simpleEditMenu(menu);
            return;
        }
        //如果上级目录改变
        if (parentChangeFlag){
            //修改前端传来的menu.level
            if (menu.getParentMenuId() == 0){
                menu.setParentMenuId(null);
                menu.setLevel(1);
            }else {
                menu.setLevel(2);
            }
            //如果是一级菜单变成二级菜单
            if (menu.getLevel() == 2 && dbMenu.getLevel() == 1){
                //检测原菜单是否有子菜单
                List<Menu> children = dbMenu.getChildren();
                if (children != null && children.size()>0){
                    //如果有子菜单当然不能更改为二级菜单,抛出异常
                    throw new RuntimeException(MessageConstant.EDIT_HASCHILDRENMENU_FAIL);
                }else {
                    //没有子菜单
                    if (menu.getParentMenuId() == menu.getId()){
                        //自己不能成为自己的二级菜单
                        throw new RuntimeException(MessageConstant.EDIT_BEMYCHILDMENU_FAIL);
                    }
                    initAddChildMenu(menu);
                    menuDao.diffcultEditMenu(menu);
                    return;
                }
            }
            //如果是二级菜单变成一级菜单
            if (menu.getLevel() == 1 && dbMenu.getLevel() == 2){
                initAddParentMenu(menu);
                menuDao.diffcultEditMenu(menu);
                return;
            }
            //如果是二级菜单变成二级菜单
            if (menu.getLevel() == 2 && dbMenu.getLevel() == 2){
                //去了别的一级菜单变成二级菜单
                initAddChildMenu(menu);
                menuDao.diffcultEditMenu(menu);
                return;
                }
                //没有一级菜单变一级菜单
            }
        //如果上级目录没有改变
        if (!parentChangeFlag){
            //如果是一级菜单
            if(menu.getLevel() == 1){
                //查看是否有子菜单
                List<Menu> children = menu.getChildren();
                initAddParentMenu(menu);
                if (children != null && children.size()>0){
                //有子菜单
                    String path = menu.getPath();
                    for (Menu child : children) {
                        child.setPath("/" + path + "-" + child.getPriority());
                        menuDao.diffcultEditMenu(child);
                    }
                }
                menuDao.diffcultEditMenu(menu);
            }else {
                //如果是二级目录
                initAddChildMenu(menu);
                menuDao.diffcultEditMenu(menu);
            }
        }
    }

    @Override
    public void deleteById(Integer id) {
        Menu menu = menuDao.findMenuById(id);
        List<Menu> children = menu.getChildren();
        if (children != null && children.size() > 0) {
            //有子菜单
            throw new RuntimeException(MessageConstant.DELETE_PARENTMENU_FAIL);
        }
        Integer count = menuDao.findCountMenuAndRoleByMenuId(id);
        if (count>0){
            //有外键
            throw new RuntimeException(MessageConstant.DELETE_ROLE_MENU_FAIL);
        }
        menuDao.deleteMenuById(id);
    }

    @Override
    public List<Menu> findAll() {
        return menuDao.findAll();
    }

    /**
     * 添加一级菜单
     * @param menu
     */
    @Override
    public void addLevel1(Menu menu) {
        menuDao.addLevel1Menu(menu);
    }

    @Override
    public List<Menu> findAllParentWithChild() {
        List<Menu> menuList = menuDao.findAllParentWithChild();
        return menuList;
    }
}
